package com.jxtc.enterprise.tenant.controller;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.jxtc.enterprise.common.aspectj.TokenRequired;
import com.jxtc.enterprise.common.constants.DefaultValueConstants;
import com.jxtc.enterprise.common.entity.DeliveryLocker;
import com.jxtc.enterprise.common.mapper.DeliverLockerMapper;
import com.jxtc.enterprise.common.utils.Result;
import com.jxtc.enterprise.common.utils.ResultGenerator;
import com.jxtc.enterprise.common.vo.CompanyVO;
import com.jxtc.enterprise.common.vo.PaginationResponseVO;
import com.jxtc.enterprise.tenant.dto.TenantCompanyCreateDTO;
import com.jxtc.enterprise.tenant.dto.TenantCompanyDTO;
import com.jxtc.enterprise.tenant.service.TenantCompanyManagementService;
import com.jxtc.enterprise.tenant.service.TenantDepartmentManagementService;
import com.jxtc.enterprise.tenant.vo.TenantCompanyDetailVO;
import com.jxtc.enterprise.tenant.vo.TenantCompanyMoreDetailVO;
import com.jxtc.enterprise.tenant.vo.companyManage.req.DeliveryLockerBindReqVo;
import com.jxtc.enterprise.tenant.vo.companyManage.req.VipUserMealSetInfoUpdateReqVo;
import com.jxtc.enterprise.tenant.vo.companyManage.resp.DeliveryLockerForCompanyRespVo;
import com.jxtc.enterprise.tenant.vo.companyManage.resp.VipUserMealSetInfoRespVo;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/jxtc/enterprise/tenant/companyManage")
@RequiredArgsConstructor
@Slf4j
public class TenantCompanyManagementController {

    private final TenantCompanyManagementService tenantCompanyManagementService;
    private final TenantDepartmentManagementService tenantDepartmentManagementService;

    private final DeliverLockerMapper deliverLockerMapper;


    @ApiResponse(responseCode = "200", description = "code 为 200 时，data 字段为包含订单列表的分页信息")
    @Parameter(name = "size", description = "每页显示的记录数，默认为 10")
    @Parameter(name = "page", description = "当前页码，从 1（默认值）开始")
    @Parameter(name = "state", description = "公司状态【所有(1)/正常供餐(2)/停止供餐(3)/已删除(4)】", example = "1")
    @Parameter(name = "companyName", description = "公司名称，如果为空查询具体公司，不为空则查询公司名称包含该字符串的公司")
    @Operation(summary = "2.2.1 租户分页查询租户所服务的公司列表", tags = "2.2 租户公司管理", operationId = "11.1")
    @GetMapping("/queryServicedCompanyForTenantByPage")
    @TokenRequired(role = TokenRequired.ROLE_TENANT)
    public Result<PaginationResponseVO<TenantCompanyDetailVO>> queryServicedCompanyForTenantByPage(@RequestParam(required = false) String companyName,
                                                                                                   @RequestParam(required = false, defaultValue = "1") Integer state,
                                                                                                   @RequestParam(required = false, defaultValue = "1") int page,
                                                                                                   @RequestParam(required = false, defaultValue = "10") int size,
                                                                                                   HttpServletRequest request) {
        String requestId = UUID.randomUUID().toString();
        // 每一次请求，生成一个唯一的请求id，将请求id放入到 ThreadLocal中，作为该接口实现逻辑中，调用栈中，各个栈帧 之间可共享的共享变量中，这样本次请求处理过程中，
        // 同一个调用栈中的各个栈帧对应的方法中，打印的requestId相同，便于查看日志时，通过唯一的requestId来将 散布在日志文件中的 日志串联起来
        // tenantCompanyManagementService.TL_REQUEST_ID.set(requestId);
        log.info("/queryServicedCompanyForTenantByPage, requestId {}, companyName: {}, state: {}", requestId, companyName, state);
        String tenantId = (String) request.getAttribute("userId");
        PaginationResponseVO<TenantCompanyDetailVO> vo = tenantCompanyManagementService.queryByPage(tenantId, companyName, state, page, size);

        log.info("/queryServicedCompanyForTenantByPage, response: {}", JSONObject.toJSONString(vo));
        return ResultGenerator.genSuccessResult(vo);
    }


    @ApiResponse(responseCode = "200", description = "若响应体中 code 为 200 表示新增公司配置信息成功，data 字段为返回的公司信息")
    @ApiResponse(responseCode = "200", description = "若响应体中 code 为 400 表示新增公司配置信息失败，message 字段则会提供错误信息")
    @Operation(summary = "2.2.2 租户新增公司接口", tags = "2.2 租户公司管理", operationId = "2.2.2")
    @PostMapping("/createCompany")
    @TokenRequired(role = TokenRequired.ROLE_TENANT)
    public Result<CompanyVO> createCompany(@Valid @RequestBody TenantCompanyCreateDTO companyCreateDTO,
                                           HttpServletRequest request) {

        String requestId = UUID.randomUUID().toString();
        log.info("/createCompany, requestId {}, request: {}", requestId, JSONObject.toJSONString(companyCreateDTO));
        String tenantId = (String) request.getAttribute("userId");
        CompanyVO companyVO = tenantCompanyManagementService.save(companyCreateDTO, tenantId);

        log.info("/createCompany, response: {}", JSONObject.toJSONString(companyVO));
        return ResultGenerator.genSuccessResult(companyVO);
    }

    @ApiResponse(responseCode = "200", description = "若响应体中 code 为 200 表示修改公司配置信息成功，data 字段为空")
    @ApiResponse(responseCode = "200", description = "若响应体中 code 为 400 表示修改公司配置信息失败，message 字段则会提供错误信息")
    @Operation(summary = "2.2.3 租户修改公司配置", tags = "2.2 租户公司管理", operationId = "2.2.3")
    @TokenRequired(role = TokenRequired.ROLE_TENANT)
    @PutMapping("/editCompany")
    public Result<Void> editCompany(@Valid @RequestBody TenantCompanyDTO dto) {
        log.info("/editCompany, request: {}", JSONObject.toJSONString(dto));
        tenantCompanyManagementService.update(dto);
        // 将部门表中的取餐地址更新成和公司一样，否则用户下单时，使用的取餐地址永远都是为公司添加部门时，公司的取餐地址；后期无论如何修改公司取餐地址，部门的取餐地址都不会变
        tenantDepartmentManagementService.batchUpdateDepartPickUpAddress(dto.getId(), dto.getAddress());
        return ResultGenerator.genSuccessResult();
    }

    @ApiResponse(responseCode = "200", description = "若响应体中 code 为 200 表示停止供餐成功，data 字段为空")
    @ApiResponse(responseCode = "200", description = "若响应体中 code 为 400 表示停止供餐失败，message 字段则会提供错误信息")
    @Parameter(name = "id", description = "公司 ID", example = "c752804d0cd410267f404dd3f0457a57")
    @Operation(summary = "2.2.4 租户停止为指定公司供餐", tags = "2.2 租户公司管理", operationId = "2.2.4")
    @TokenRequired(role = TokenRequired.ROLE_TENANT)
    @PutMapping("/{id}/cancel")
    public Result<Void> cancelFeeding(@PathVariable("id") String id) {
        log.info("/companyManage/{}/cancel", id);
        tenantCompanyManagementService.supply(id, true);
        return ResultGenerator.genSuccessResult();
    }

    @ApiResponse(responseCode = "200", description = "若响应体中 code 为 200 表示重新供餐成功，data 字段为空")
    @ApiResponse(responseCode = "200", description = "若响应体中 code 为 400 表示重新供餐失败，message 字段则会提供错误信息")
    @Parameter(name = "id", description = "公司 ID", example = "c752804d0cd410267f404dd3f0457a57")
    @Operation(summary = "2.2.5 租户为指定公司重新供餐", tags = "2.2 租户公司管理", operationId = "2.2.5")
    @TokenRequired(role = TokenRequired.ROLE_TENANT)
    @PutMapping("/{id}/supply")
    public Result<Void> supplyFeeding(@PathVariable("id") String id) {
        log.info("/companyManage/{}/supply", id);
        tenantCompanyManagementService.supply(id, false);
        return ResultGenerator.genSuccessResult();
    }

    @ApiResponse(responseCode = "200", description = "若响应体中 code 为 200 表示删除公司成功，data 字段为空")
    @ApiResponse(responseCode = "200", description = "若响应体中 code 为 400 表示删除公司失败，message 字段则会提供错误信息")
    @Parameter(name = "id", description = "公司 ID", example = "c752804d0cd410267f404dd3f0457a57")
    @Operation(summary = "2.2.6 租户软删除指定公司", tags = "2.2 租户公司管理", operationId = "2.2.6")
    @TokenRequired(role = TokenRequired.ROLE_TENANT)
    @DeleteMapping("/deleteCompany/{id}")
    public Result<Void> softDeleteCompany(@PathVariable("id") String id) {
        String requestId = UUID.randomUUID().toString();
        log.info("/deleteCompany/{}, requestId {}", id, requestId);
        tenantCompanyManagementService.softDelete(id);
        return ResultGenerator.genSuccessResult();
    }

    @ApiResponse(responseCode = "200", description = "若响应体中 code 为 200 表示查询公司信息成功，data 字段为公司信息")
    @ApiResponse(responseCode = "200", description = "若响应体中 code 为 400 表示查询公司信息失败，message 字段则会提供错误信息")
    @Parameter(name = "id", description = "公司 ID", example = "c752804d0cd410267f404dd3f0457a57")
    @Operation(summary = "2.2.7 根据公司 ID 查询公司详细配置", tags = "2.2 公司配置", operationId = "2.2.7")
    @TokenRequired(role = TokenRequired.ROLE_TENANT)
    @GetMapping("/queryCompanyDetailByIdFromTenant/{companyId}")
    public Result<TenantCompanyMoreDetailVO> queryCompanyDetailByIdFromTenant(@PathVariable("companyId") String companyId, HttpServletRequest request) {
        String requestId = UUID.randomUUID().toString();
        log.info("/queryCompanyDetailByIdFromTenant/{}, requestId {}", companyId, requestId);
        String tenantId = (String) request.getAttribute("userId");
        TenantCompanyMoreDetailVO vo = tenantCompanyManagementService.queryCompanyDetailByCompanyId(companyId, tenantId);
        return ResultGenerator.genSuccessResult(vo);
    }


    /**
     * 2.2.8 查询指定公司绑定的外卖柜列表
     *
     * @param companyId 公司 ID
     */
    @TokenRequired(role = TokenRequired.ROLE_TENANT)
    @GetMapping("/queryDeliveryLockerListForCompany")
    public Result<List<DeliveryLockerForCompanyRespVo>> queryDeliveryLockerListForCompany(@RequestParam(value = "companyId") String companyId) {
        log.info("/queryDeliveryLockerListForCompany, companyId: {}", companyId);

        LambdaQueryWrapper<DeliveryLocker> deliveryLockerQueryWrapper = new LambdaQueryWrapper<DeliveryLocker>()
                .eq(DeliveryLocker::getCompanyId, companyId)
                .eq(DeliveryLocker::getDelFlag, false)
                .orderByDesc(DeliveryLocker::getCreateTime);
        List<DeliveryLocker> deliveryLockerList = deliverLockerMapper.selectList(deliveryLockerQueryWrapper);
        List<DeliveryLockerForCompanyRespVo> voList = deliveryLockerList.stream()
                .map(this::buildDeliveryLockerForCompanyRespVo)
                .collect(Collectors.toList());

        log.info("/queryDeliveryLockerListForCompany, response: {}", JSONObject.toJSONString(voList));
        return ResultGenerator.genSuccessResult(voList);
    }

    private DeliveryLockerForCompanyRespVo buildDeliveryLockerForCompanyRespVo(DeliveryLocker deliveryLocker) {
        DeliveryLockerForCompanyRespVo vo = new DeliveryLockerForCompanyRespVo();
        vo.setDeliveryLockerId(deliveryLocker.getId());
        vo.setDeliveryLockerName(deliveryLocker.getName());
        vo.setDeliveryLockerShortName(deliveryLocker.getShortName());
        vo.setClientNo(deliveryLocker.getClientNo());
        vo.setAppId(deliveryLocker.getAppId());
        vo.setAppKey(deliveryLocker.getAppKey());
        vo.setCab(deliveryLocker.getCab());
        vo.setColStart(deliveryLocker.getColStart());
        vo.setColEnd(deliveryLocker.getColEnd());
        return vo;
    }

    /**
     * 2.2.9 查询指定公司未绑定的外卖柜列表
     *
     * @param companyId 公司 ID
     */
    @TokenRequired(role = TokenRequired.ROLE_TENANT)
    @GetMapping("/queryDeliveryLockerNotBoundListForCompany")
    public Result<List<DeliveryLockerForCompanyRespVo>> queryDeliveryLockerNotBoundList(@RequestParam(value = "companyId") String companyId, HttpServletRequest request) {
        String tenantId = (String) request.getAttribute("userId");
        log.info("/queryDeliveryLockerNotBoundListForCompany, companyId: {}, tenantId: {}", companyId, tenantId);

        LambdaQueryWrapper<DeliveryLocker> deliveryLockerQueryWrapper = new LambdaQueryWrapper<DeliveryLocker>()
                .ne(DeliveryLocker::getCompanyId, companyId)
                .eq(DeliveryLocker::getTenantId, tenantId)
                .eq(DeliveryLocker::getDelFlag, false)
                .orderByDesc(DeliveryLocker::getCreateTime);
        List<DeliveryLocker> deliveryLockerList = deliverLockerMapper.selectList(deliveryLockerQueryWrapper);
        List<DeliveryLockerForCompanyRespVo> voList = deliveryLockerList.stream()
                // 仅展示尚未绑定公司的外卖柜
                .filter(deliveryLocker -> DefaultValueConstants.DELIVERY_LOCKER_NOT_BOUND_COMPANY_ID.equals(deliveryLocker.getCompanyId()))
                .map(this::buildDeliveryLockerForCompanyRespVo)
                .collect(Collectors.toList());

        log.info("/queryDeliveryLockerNotBoundListForCompany, response: {}", JSONObject.toJSONString(voList));
        return ResultGenerator.genSuccessResult(voList);
    }


    /**
     * 2.2.10 绑定外卖柜到公司
     *
     * @param reqVo 公司 ID 和外卖柜 ID 列表
     */
    @TokenRequired(role = TokenRequired.ROLE_TENANT)
    @PostMapping("/bindDeliveryLockerForCompany")
    public Result<Void> bindDeliveryLockerForCompany(@Valid @RequestBody DeliveryLockerBindReqVo reqVo) {
        log.info("/bindDeliveryLockerForCompany, request: {}", JSONObject.toJSONString(reqVo));
        tenantCompanyManagementService.bindDeliveryLockerForCompany(reqVo.getCompanyId(), reqVo.getDeliveryLockerIdList());
        return ResultGenerator.genSuccessResult();
    }


    /**
     * 2.2.11 解绑外卖柜
     *
     * @param deliveryLockerId 外卖柜 ID
     */
    @TokenRequired(role = TokenRequired.ROLE_TENANT)
    @GetMapping("/cancelBindDeliveryLockerForCompany")
    public Result<Void> cancelBindDeliveryLockerForCompany(@RequestParam(value = "deliveryLockerId") String deliveryLockerId) {
        log.info("/cancelBindDeliveryLockerForCompany, deliveryLockerId: {}", deliveryLockerId);
        DeliveryLocker deliveryLockerSaved = deliverLockerMapper.selectById(deliveryLockerId);
        if (deliveryLockerSaved == null) {
            // 如果外卖柜不存在，返回错误提示信息
            log.warn("/cancelBindDeliveryLockerForCompany, 外卖柜不存在，deliveryLockerId: {}", deliveryLockerId);
            return ResultGenerator.genFailResult("ID 为 " + deliveryLockerId + " 的外卖柜不存在");
        }

        DeliveryLocker deliveryLockerUpdate = new DeliveryLocker();
        deliveryLockerUpdate.setId(deliveryLockerId);
        // 将公司 ID 设置为 32 个 0 来表示该外卖柜暂未绑定公司
        deliveryLockerUpdate.setCompanyId(DefaultValueConstants.DELIVERY_LOCKER_NOT_BOUND_COMPANY_ID);
        int updateCount = deliverLockerMapper.updateById(deliveryLockerUpdate);
        if (updateCount != 1) {
            // 如果更新失败，返回错误提示信息
            log.error("/cancelBindDeliveryLockerForCompany, 更新失败，deliveryLockerId: {}, updateCount: {}", deliveryLockerId, updateCount);
            return ResultGenerator.genFailResult("解绑外卖柜失败，请稍后重试");
        }

        return ResultGenerator.genSuccessResult();
    }


    /**
     * 2.2.13 通过公司 ID 查询该公司的客户餐相关配置信息
     *
     * @param companyId 公司 ID
     */
    @TokenRequired(role = TokenRequired.ROLE_TENANT)
    @GetMapping("/queryVipUserMealSetInfoByCompanyId")
    public Result<VipUserMealSetInfoRespVo> queryVipUserMealSetInfoByCompanyId(@RequestParam("companyId") String companyId) {
        String requestId = UUID.randomUUID().toString();
        log.info("requestId {}, tenant view, /queryVipUserMealSetInfoByCompanyId, companyId: {}", requestId, companyId);
        VipUserMealSetInfoRespVo vo = tenantCompanyManagementService.queryVipUserMealSetInfoByCompanyId(companyId, requestId);
        log.info("requestId {}, tenant view, /queryVipUserMealSetInfoByCompanyId, response: {}", requestId, JSONObject.toJSONString(vo));
        return ResultGenerator.genSuccessResult(vo);
    }


    /**
     * 2.2.14 通过公司 ID 更新该公司的客户餐相关配置信息
     */
    @TokenRequired(role = TokenRequired.ROLE_TENANT)
    @PostMapping("/editVipUserMealSetInfoByCompanyId")
    public Result<Void> editVipUserMealSetInfoByCom(@Valid @RequestBody VipUserMealSetInfoUpdateReqVo reqVo) {
        String requestId = UUID.randomUUID().toString();
        log.info("requestId {}, tenant view, /editVipUserMealSetInfoByCompanyId, request: {}", requestId, JSONObject.toJSONString(reqVo));
        tenantCompanyManagementService.editVipUserMealSetInfoByCompanyId(reqVo, requestId);
        return ResultGenerator.genSuccessResult();
    }
}
